<?php

namespace app\logic\subscribe;

use app\common\model\subscribe\Subscribe;
use app\common\model\subscribe\SubscribeSettings;
use app\common\model\User;
use app\logic\BaseLogic;

class SubscribeLogic extends BaseLogic
{
    //订阅设置字段
    const SUBSCRIBE_FIELDS = [
        //现价
        'price' => 0,
        //原价
        'original_price' => 0,
        //用于标记配置的状态，是否启用（1）或禁用（0）
        'status' => 0
    ];

    /**
     * 订阅
     * @param array $params 参数
     * @param int $userId 当前登录的人ID
     * @return bool
     * @throws \Throwable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function subscribe($params, $userId): bool
    {
        $model = Subscribe::initModel();
        $find = $model->where('user_id', $userId)
            ->where('subscribe_user_id', $params['user_id'])
            ->find();
        if (!$find) {
            $model->insert([
                'user_id' => $userId,
                'subscribe_user_id' => $params['user_id'],
                'start_time' => time(),
                'expire_time' => strtotime('+1 month')
            ]);
        }

        return true;
    }

    /**
     * 是否订阅
     * @param mixed $creatorId 达人ID
     * @param mixed $userId 当前登录者ID
     * @return false
     * @throws \Throwable
     */
    public function isSubscribe(mixed $creatorId, mixed $userId): bool
    {
        $count = Subscribe::initModel()->where(['subscribe_user_id' => $creatorId, 'user_id' => $userId])->count();
        return $count > 0;
    }

    /**
     * 达人ID获取订阅数
     * @param mixed $creatorId
     * @return int
     * @throws \Throwable
     */
    public function getSubscribeCount(mixed $creatorId): int
    {
        return Subscribe::initModel()->where(['subscribe_user_id' => $creatorId])->count();
    }

    /**
     * 获取订阅设置
     * @param $userId
     * @return SubscribeSettings|array|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getSetting($userId): SubscribeSettings|array|\think\Model|null
    {
        return SubscribeSettings::initModel()->find($userId);
    }

    /**
     * 保存订阅设置
     * @param $params
     * @param $userId
     * @return SubscribeSettings|bool
     * @throws \Throwable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    /**
     * 设置用户订阅偏好
     *
     * 该方法用于更新或创建用户的订阅设置，包括年费、季费、月费的配置以及促销信息
     * 它首先处理传入的参数，然后根据用户ID查找或初始化订阅设置模型，并更新数据库
     *
     * @param array $params 包含用户订阅偏好的参数数组，包括年费、季费、月费详细信息及促销信息
     * @param int|string $userId 用户ID，用于查找或创建订阅设置
     *
     * @return SubscribeSettings|bool
     * @throws \Throwable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function setSettings(array $params, int|string $userId): SubscribeSettings|bool
    {
        // 初始化订阅周期数组，用于存储不同周期的订阅字段值
        $yearly = [];
        $quarterly = [];
        $monthly = [];

        // 遍历订阅字段常量，为每个订阅周期赋值
        foreach (self::SUBSCRIBE_FIELDS as $field => $val) {
            $yearly[$field] = $params['yearly'][$field] ?? $val;
            $quarterly[$field] = $params['quarterly'][$field] ?? $val;
            $monthly[$field] = $params['monthly'][$field] ?? $val;
        }

        // 初始化订阅设置模型，并尝试查找用户现有的订阅设置
        $model = SubscribeSettings::initModel($userId);
        // 尝试查找用户现有的订阅设置
        $find = $model->find($userId);

        // 准备要保存的数据数组，包括用户ID、订阅周期数据和促销信息
        $data = [
            //用户ID
            'user_id' => $userId,
            //年度
            'yearly' => json_encode($yearly),
            //季度
            'quarterly' => json_encode($quarterly),
            //月度
            'monthly' => json_encode($monthly),
            //是否促销
            'is_on_sale' => $params['is_on_sale'],
            //订阅优惠折扣
            'discount' => $params['discount'],
            //订阅优惠文案
            'promotion_text' => $params['promotion_text'],
        ];

        // 根据查找结果决定是更新现有设置还是保存新的设置
        return $find ? $model->where('user_id', $userId)->update($data) : $model->save($data);
    }

    /**
     * 检查订阅是否至少有一个开关打开
     * @param $userId
     * @return bool
     * @throws \Throwable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function checkSettings($userId)
    {
        // 获取用户订阅设置
        $settings = SubscribeSettings::initModel($userId)->find($userId);

        // 如果未找到设置，直接返回 false
        if (!$settings) {
            return false;
        }

        // 检查所有订阅状态是否都为 0
        $statuses = [$settings->yearly['status'], $settings->quarterly['status'], $settings->monthly['status']];
        return !empty(array_filter($statuses));
    }

    /**
     * 我的订阅达人
     * @param string|int $userId
     * @param int $limit
     * @return array
     * @throws \Throwable
     * @throws \think\db\exception\DbException
     */
    public function mySubscribe(string|int $userId, int $limit = 10)
    {
        $uids = Subscribe::initModel()->where(['user_id' => $userId])->column('subscribe_user_id');

        $user = User::initModel()->whereIn('id', $uids)->limit($limit)->field('id, avatar, nickname, motto')->paginate($limit);

        return $user->toArray();
    }

    /**
     * 订阅我的人
     * @param $userId
     * @param $limit
     * @return array
     * @throws \Throwable
     * @throws \think\db\exception\DbException
     */
    public function subscribeMe($userId, $limit)
    {
        $uids = Subscribe::initModel()->where(['subscribe_user_id' => $userId])->column('user_id');

        $user = User::initModel()->whereIn('id', $uids)->limit($limit)->field('id, avatar, nickname, motto')->paginate($limit);

        return $user->toArray();
    }
}